/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "http2_napi.h"
#include "http2_common.h"
#include "http2_constant.h"
#include "napi/http2_constant.h"
#include "ohos_log.h"
#include <cstddef>
#include <thread>

RequestCallback* HandleRequestCallback(int type, void *data, int len, int reqType, std::string reqId)
{
    void *swapData = nullptr;
    char *responseHeaders = nullptr;
    uint8_t *responseDataTrunck = nullptr;
    int errorCode = 0;
    int lastStreamId = 0;
    if (type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE || type == HTTP_STREAM_CALLBACK_TYPE_ERROR ||
        type == HTTP_CALLBACK_TYPE_CLOSE) {
        int allocLen = strlen((char *)data) + 1;
        if (len >= 0 && len <= MAX_ALLOC_SIZE) {
            responseHeaders = (char *)malloc(allocLen);
            std::copy((uint8_t *)data, (uint8_t *)data + allocLen, responseHeaders);
            swapData = responseHeaders;
        }
    }
    if (type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) {
        if (len >= 0 && len <= MAX_ALLOC_SIZE) {
            responseDataTrunck = (uint8_t *)malloc(len + 1);
            std::copy((uint8_t *)data, (uint8_t *)data + len + 1, responseDataTrunck);
            swapData = responseDataTrunck;
        }
    }
    if (g_callbackManagerMap.find(reqId) == g_callbackManagerMap.end()) {
        return nullptr;
    }
    auto env = g_envManagerMap.at(reqId);
    auto callbackRef = g_callbackManagerMap.at(reqId);
    LOGE("HandleRequestCallback %p type %d reqId %s ", callbackRef, type, reqId.c_str());
    RequestCallback *requestCallback = new RequestCallback{.env = env,
                                                           .callbackRef = callbackRef,
                                                           .type = type,
                                                           .errorCode = errorCode,
                                                           .reqId = reqId,
                                                           .lastStreamId = lastStreamId,
                                                           .data = swapData,
                                                           .dataLen = len,
                                                           .reqType = reqType};
    return requestCallback;
}

void HandleResponseData(RequestCallback *requestCallback, napi_value* dataNV)
{
    if (requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE ||
        requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_ERROR ||
        requestCallback->type == HTTP_CALLBACK_TYPE_CLOSE) {
        napi_create_string_utf8(requestCallback->env, (char *)requestCallback->data, NAPI_AUTO_LENGTH, dataNV);
    }
    if (requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) {
        if (requestCallback->reqType == 1 && requestCallback->dataLen > NUM_5) {
            uint8_t *tempData = (uint8_t *)requestCallback->data;
            size_t startIndex = INDEX_5;
            size_t copyLength =  requestCallback->dataLen - INDEX_5;
            if (copyLength > MAX_ALLOC_SIZE || copyLength < 0) {
                return;
            }
            uint8_t *clippedData = (uint8_t *)malloc(copyLength);
            std::copy(tempData + startIndex, tempData + startIndex + copyLength, clippedData);
            CreateArrayBuffer(requestCallback->env, clippedData, copyLength, dataNV);
            if (clippedData) {
                free(clippedData);
                clippedData = nullptr;
            }
        } else {
            CreateArrayBuffer(requestCallback->env, requestCallback->data, requestCallback->dataLen, dataNV);
        }
    }
}

bool ReadWriteBuffer(struct pollfd* pollfds, int npollfds, Connection& connection,
    RequestTask* requestTask, bool& streamError)
{
    int nfds = poll(pollfds, npollfds, NUM_30000);
    if (nfds == -1) {
        LOGE("poll %s", strerror(errno));
    }
    if (pollfds[0].revents & (POLLIN | POLLOUT)) {
        auto handleIoResult = HandleIo(connection.session, requestTask->reqId);
        if (handleIoResult.code < 0) {
            LOGE("HandleIo error reqId %s", requestTask->reqId.c_str());
            if (handleIoResult.isRecv) {
                streamError = true;
            } else {
                g_postEvent(HTTP_STREAM_CALLBACK_TYPE_END, nullptr, 0, 1, requestTask->reqId);
            }
            return true;
        }
    }
    if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
        LOGE("nghttp2_session_want_read error reqId %s", requestTask->reqId.c_str());
        streamError = true;
        return true;
    }
    CtlPoll(pollfds, connection.session, connection.wantIo);
    return false;
}

void HandleWrite(RequestTask *requestTask)
{
    std::string reqId = requestTask->reqId;
    LOGE("napi-->Write reqId :%s fd %d", reqId.c_str(), requestTask->fd);
    struct Connection connection;
    connection.host = requestTask->host;
    connection.path = requestTask->path;
    connection.reqId = requestTask->reqId;
    int rv = HandleSSLShake(&connection, requestTask->fd, requestTask->host);
    if (rv < 0) {
        LOGE("HandleSSLShake Error reqId :%s", reqId.c_str());
        std::string error = "Error handshake failed";
        g_postEvent(HTTP_STREAM_CALLBACK_TYPE_ERROR, const_cast<char *>(error.c_str()), 0, 1, requestTask->reqId);
        return;
    }
    nfds_t npollfds = 1;
    struct pollfd pollfds[1];
    g_connectManagerMap[reqId] = &connection;
    SendData(&connection, requestTask->buff, requestTask->buffLen, requestTask->extendParams);
    pollfds[0].fd = requestTask->fd;
    CtlPoll(pollfds, connection.session, connection.wantIo);
    bool streamError = false;
    while (!g_streamCloseManagerMap[requestTask->reqId]) {
        if (requestTask->fd < 0 || IsDestroyed(requestTask->reqId)) {
            break;
        }
        if (nghttp2_session_want_read(connection.session) || nghttp2_session_want_write(connection.session)) {
            LOGE("the message task enters the reading or writing state reqId %s", requestTask->reqId.c_str());
            bool result = ReadWriteBuffer(pollfds, npollfds, connection, requestTask, streamError);
            if (result) {
                break;
            }
        }
    }
    LOGE("the message task end close %d reqId %s", g_streamCloseManagerMap[requestTask->reqId],
         requestTask->reqId.c_str());
    if (streamError) {
        std::string error = "-1";
        g_postEvent(HTTP_STREAM_CALLBACK_TYPE_ERROR, const_cast<char *>(error.c_str()), 0, 1, requestTask->reqId);
    }
    if (IsDestroyed(requestTask->reqId)) {
        return;
    }
    FreeResource(&connection);
}

void HandleEnd(void *data)
{
    Connection *connection = (Connection *)data;
    LOGE("HandleEnd reqId %s", connection->reqId.c_str());
    time_t startTime = time(nullptr);
    if (connection->reqId.empty() || !CheckReqId(connection->reqId)) {
        return;
    }
    while (g_streamCloseManagerMap.find(connection->reqId) == g_streamCloseManagerMap.end()) {
        for (const auto &child : g_streamCloseManagerMap) {
            if (child.first == connection->reqId) {
                break;
            }
        }
        LOGE("streamCloseManagerMap reqId %s", connection->reqId.c_str());
        usleep(NUM_100);
        time_t currentTime = time(nullptr);
        // 5秒之后如果没有检测到close 直接退出
        if (TimeDifference(startTime, currentTime) > NUM_5) {
            break;
        }
    }
    if (g_freeManagerMap.find(connection->reqId) != g_freeManagerMap.end()) {
        LOGE("freeManagerMap find success reqId %s len %d", connection->reqId.c_str(), g_callbackManagerMap.size());
        g_freeManagerMap.erase(connection->reqId);
        return;
    }
    g_postEvent(HTTP_CALLBACK_TYPE_CLOSE, const_cast<char *>("0"),
        0, connection->reqType, connection->reqId);
    usleep(NUM_2 * NUM_1000);
    FreeResource(connection);
    LOGE("HandleEnd remove success len %d reqId %s", g_callbackManagerMap.size(), connection->reqId.c_str());
}

void CallJs(uv_work_t *work)
{
    if (!work) {
        return;
    }
    RequestCallback *requestCallback = (RequestCallback *)(work->data);
    napi_handle_scope scope = nullptr;
    if (!requestCallback || !requestCallback->env) {
        return;
    }
    napi_open_handle_scope(requestCallback->env, &scope);
    if (!requestCallback || !requestCallback->env || !requestCallback->callbackRef ||
        g_callbackManagerMap.find(requestCallback->reqId) == g_callbackManagerMap.end()) {
        FreeRequestCallback(requestCallback);
        delete work;
        return;
    }
    napi_value reqIdNV;
    napi_value typeNV;
    napi_value dataNV;
    napi_create_int32(requestCallback->env, requestCallback->type, &typeNV);
    HandleResponseData(requestCallback, &dataNV);
    napi_value ret = 0;
    napi_value callback = nullptr;
    LOGE("napi-->uv_queue_work reqId %s type %d callback %p", requestCallback->reqId.c_str(),
         requestCallback->type, requestCallback->callbackRef);
    napi_create_string_utf8(requestCallback->env, requestCallback->reqId.c_str(), NAPI_AUTO_LENGTH, &reqIdNV);
    napi_get_reference_value(requestCallback->env, requestCallback->callbackRef, &callback);
    if ((requestCallback->type != HTTP_STREAM_CALLBACK_TYPE_END) && dataNV) {
        napi_value argv_3[] = {reqIdNV, typeNV, dataNV};
        napi_call_function(requestCallback->env, nullptr, callback, NUM_3, argv_3, &ret);
        if (requestCallback->data && (requestCallback->type != HTTP_STREAM_CALLBACK_TYPE_GOWAY)) {
            free(requestCallback->data);
            requestCallback->data = nullptr;
        }
    } else {
        napi_value argv_2[] = {reqIdNV, typeNV};
        napi_call_function(requestCallback->env, nullptr, callback, NUM_2, argv_2, &ret);
    }
    napi_close_handle_scope(requestCallback->env, scope);
    delete work;
    FreeRequestCallback(requestCallback);
}

void OnEventListener(int type, void *data, int len, int reqType, std::string requestId)
{
    RequestCallback *requestCallback = HandleRequestCallback(type, data, len, reqType, requestId);
    uv_loop_s *loopMessage = nullptr;
    if (g_envManagerMap.find(requestId) == g_envManagerMap.end()) {
        FreeRequestCallback(requestCallback);
        return;
    }
    napi_get_uv_event_loop(g_envManagerMap.at(requestId), &loopMessage);
    if (loopMessage == nullptr) {
        FreeRequestCallback(requestCallback);
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        FreeRequestCallback(requestCallback);
        return;
    }
    work->data = requestCallback;
    uv_queue_work(
        loopMessage, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            CallJs(work);
        });
}

RequestTask* HandleRequestParams(napi_env env, napi_callback_info info)
{
    std::string reqId;
    std::string host;
    napi_deferred deferred;
    std::string path;
    std::string extendParams;
    size_t argc = PARAM_COUNT_5;
    napi_value args[PARAM_COUNT_5] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    NapiUtil::JsValueToString(env, args[INDEX_1], STR_DEFAULT_SIZE, host);
    NapiUtil::JsValueToString(env, args[INDEX_2], STR_DEFAULT_SIZE, path);
    NapiUtil::JsValueToString(env, args[INDEX_3], STR_DEFAULT_SIZE, extendParams);
    napi_value callback = args[INDEX_4];
    napi_ref callBackRefMessage;
    napi_create_reference(env, callback, 1, &callBackRefMessage);
    SetEnvMessage(reqId, env);
    SetCallBackRef(reqId, callBackRefMessage);
    MessageCallback(OnEventListener);
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    RequestTask *requestTask = new RequestTask{
        .env = env,
        .asyncWork = nullptr,
        .deferred = deferred,
        .reqId = reqId,
        .host = host,
        .path = path,
        .extendParams = extendParams,
        .promise = promise
    };
    g_requestManagerMap[reqId] = requestTask;
    return requestTask;
}

int Http2Napi::ConnectTo(const char *host, uint16_t port)
{
    LOGE("ConnectTo host %s port %d", host, port);
    struct addrinfo hints;
    int fd = -1;
    int rv;
    char service[NI_MAXSERV];
    struct addrinfo *res;
    struct addrinfo *rp;
    rv = snprintf_s(service, sizeof(service), sizeof(service), "%u", port);
    if (rv < 0) {
        return -1;
    }
    memset_s(&hints, sizeof(struct addrinfo), 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    rv = getaddrinfo(host, service, &hints, &res);
    if (rv != 0) {
        LOGE("getaddrinfo %s", gai_strerror(rv));
        return -1;
    }
    for (rp = res; rp; rp = rp->ai_next) {
        fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (fd == -1) {
            continue;
        }
        while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && errno == EINTR) {
            if (rv < 0) {
                LOGE("connect rv %d", rv);
            }
        }
        if (rv == 0) {
            break;
        }
        close(fd);
        fd = -1;
    }
    freeaddrinfo(res);
    return fd;
}

napi_value Http2Napi::ClassConstructor(napi_env env, napi_callback_info info)
{
    LOGE("napi-->ClassConstructor");
    napi_value targetObj = nullptr;
    size_t argc = PARAM_COUNT_0;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, &targetObj, nullptr);
    Http2Napi *http2Napi = new Http2Napi();
    napi_wrap(
        env, nullptr, http2Napi,
        [](napi_env env, void *data, void *hint) {
            Http2Napi *http2NapiObj = (Http2Napi *)data;
            delete http2NapiObj;
            http2NapiObj = nullptr;
        },
        nullptr, nullptr);
    return targetObj;
}


napi_value Http2Napi::Connect(napi_env env, napi_callback_info info)
{
    LOGE("napi-->Connect");
    size_t argc = PARAM_COUNT_2;
    napi_value args[PARAM_COUNT_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    std::string port;
    NapiUtil::JsValueToString(env, args[INDEX_1], STR_DEFAULT_SIZE, port);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value resourceName;
    napi_create_string_latin1(env, "connect", NAPI_AUTO_LENGTH, &resourceName);
    RequestTask *requestTask =
        new RequestTask{.env = env, .asyncWork = nullptr, .deferred = deferred, .host = host, .port = port};
    napi_create_async_work(
        env, nullptr, resourceName,
        [](napi_env env, void *data) {
        },
        [](napi_env env, napi_status status, void *data) {
            LOGE("napi-->Connect fd success");
            RequestTask *requestTask = (RequestTask *)data;
            napi_value result;
            napi_create_int32(env, 0, &result);
            napi_resolve_deferred(requestTask->env, requestTask->deferred, result);
            napi_delete_async_work(env, requestTask->asyncWork);
            delete requestTask;
            requestTask = nullptr;
        },
        requestTask, &requestTask->asyncWork);
    napi_queue_async_work(env, requestTask->asyncWork);
    return promise;
}

napi_value Http2Napi::Request(napi_env env, napi_callback_info info)
{
    RequestTask *requestTask = HandleRequestParams(env, info);
    LOGE("napi--->Request reqId %s", requestTask->reqId.c_str());
    napi_value resourceName;
    napi_create_string_latin1(env, "request", NAPI_AUTO_LENGTH, &resourceName);
    napi_create_async_work(
        env, nullptr, resourceName,
        [](napi_env env, void *data) {
        },
        [](napi_env env, napi_status status, void *data) {
            RequestTask *requestTask = (RequestTask *)data;
            napi_value result;
            napi_create_string_utf8(env, requestTask->reqId.c_str(), NAPI_AUTO_LENGTH, &result);
            napi_resolve_deferred(requestTask->env, requestTask->deferred, result);
            napi_delete_async_work(env, requestTask->asyncWork);
        },
        requestTask, &requestTask->asyncWork);
    napi_queue_async_work(env, requestTask->asyncWork);
    return requestTask->promise;
}

napi_value Http2Napi::Write(napi_env env, napi_callback_info info)
{
    size_t argc = PARAM_COUNT_2;
    napi_value args[PARAM_COUNT_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string reqId;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    void *buffer;
    size_t bufferLen;
    napi_get_arraybuffer_info(env, args[INDEX_1], &buffer, &bufferLen);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value resourceName;
    napi_create_string_latin1(env, "write", NAPI_AUTO_LENGTH, &resourceName);
    LOGE("napi--->Write reqId %s env %p", reqId.c_str(), env);
    if (g_requestManagerMap.find(reqId) == g_requestManagerMap.end()) {
        return promise;
    }
    RequestTask *requestTask = g_requestManagerMap.at(reqId);
    if (requestTask->host.size() <= 0 || requestTask->host.size() > NUM_1000) {
        return promise;
    }
    RequestTask *requestTask2 = new RequestTask{.env = env, .asyncWork = nullptr, .deferred = deferred,
                                                .host = requestTask->host, .path = requestTask->path,
                                                .buff = buffer, .reqId = reqId,
                                                .extendParams = requestTask->extendParams,
                                                .buffLen = static_cast<int>(bufferLen)};
    napi_create_async_work(
        env, nullptr, resourceName,
        [](napi_env env, void *data) {
           RequestTask *requestTask = (RequestTask *)data;
           auto domain = ParseDomain(requestTask->host);
           int fd = Http2Napi::ConnectTo(domain.host.c_str(), NapiUtil::StringToInt(domain.port.c_str()));
           requestTask->fd = fd;
           if (!requestTask) return;
           g_sessionManagerMap[requestTask->reqId] = 0;
           HandleWrite(requestTask);
        },
        [](napi_env env, napi_status status, void *data) {
           EndWriteTask(env, data);
        }, requestTask2, &requestTask2->asyncWork);
    napi_queue_async_work(env, requestTask2->asyncWork);
    return promise;
}

napi_value Http2Napi::End(napi_env env, napi_callback_info info)
{
    size_t argc = PARAM_COUNT_2;
    napi_value args[PARAM_COUNT_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string reqId;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    LOGE("napi--->End reqId %s", reqId.c_str());
    if (g_freeManagerMap.find(reqId)!=g_freeManagerMap.end() && g_freeManagerMap.at(reqId)) {
        g_sessionManagerMap[reqId] = 1;
        LOGE("Error End reqId %s already free", reqId.c_str());
        g_freeManagerMap.erase(reqId);
        return nullptr;
    }
    auto resIt = g_connectManagerMap.find(reqId);
    if (resIt != g_connectManagerMap.end()) {
        if (g_sessionManagerMap.find(reqId) == g_sessionManagerMap.end()) {
            return nullptr;
        }
        g_sessionManagerMap[reqId] = 1;
        napi_deferred deferred;
        napi_value promise;
        napi_create_promise(env, &deferred, &promise);
        napi_value resourceName;
        napi_create_string_latin1(env, "end", NAPI_AUTO_LENGTH, &resourceName);
        Connection *connection = g_connectManagerMap.at(reqId);
        if (!connection || !CheckReqId(connection->reqId)) {
            return nullptr;
        }
        Connection *connectionTemp = new Connection{.ssl = connection->ssl,
                                                 .fd = connection->fd,
                                                 .reqId = connection->reqId,
                                                 .sslCtx = connection->sslCtx,
                                                 .env = env,
                                                 .deferred = deferred,
                                                 .session = connection->session};
        napi_create_async_work(
            env, nullptr, resourceName,
            [](napi_env env, void *data) {
               HandleEnd(data);
            },
            [](napi_env env, napi_status status, void *data) {
               EndStreamTask(env, data);
            }, connectionTemp, &connectionTemp->asyncWork);
        napi_queue_async_work(env, connectionTemp->asyncWork);
        return promise;
    } else {
        LOGE("Error End reqId %s", reqId.c_str());
    }
    return nullptr;
}

napi_value Http2Napi::DnsResolveTxt(napi_env env, napi_callback_info info)
{
    LOGE("napi-->DnsResolveTxt");
    size_t argc = PARAM_COUNT_1;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value resourceName;
    napi_create_string_latin1(env, "DnsResolveTxt", NAPI_AUTO_LENGTH, &resourceName);
    RequestTask *requestTask = new RequestTask{.env = env, .asyncWork = nullptr, .deferred = deferred, .host = host};
    napi_create_async_work(
        env, nullptr, resourceName,
        [](napi_env env, void *data) {
            RequestTask *requestTask = (RequestTask *)data;
            auto result = ResolveHostTxt(requestTask->host);
            for (std::vector<std::string>::iterator it = result.begin(); it != result.end(); ++it) {
                requestTask->dnsText.append(*it);
            }
        },
        [](napi_env env, napi_status status, void *data) {
            LOGE("napi-->DnsResolveTxt success");
            RequestTask *requestTask = (RequestTask *)data;
            napi_value result;
            napi_create_string_utf8(env, requestTask->dnsText.c_str(), NAPI_AUTO_LENGTH, &result);
            napi_resolve_deferred(requestTask->env, requestTask->deferred, result);
            napi_delete_async_work(env, requestTask->asyncWork);
            delete requestTask;
            requestTask = nullptr;
        },
        requestTask, &requestTask->asyncWork);
    napi_queue_async_work(env, requestTask->asyncWork);
    return promise;
}

napi_value Http2Napi::DnsLookup(napi_env env, napi_callback_info info)
{
    LOGE("napi-->DnsLookup");
    size_t argc = PARAM_COUNT_1;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value resourceName;
    napi_create_string_latin1(env, "DnsLookup", NAPI_AUTO_LENGTH, &resourceName);
    RequestTask *requestTask = new RequestTask{.env = env, .asyncWork = nullptr, .deferred = deferred, .host = host};
    napi_create_async_work(
        env, nullptr, resourceName,
        [](napi_env env, void *data) {
            RequestTask *requestTask = (RequestTask *)data;
            requestTask->dnsText = FindIPAddr(requestTask->host);
        },
        [](napi_env env, napi_status status, void *data) {
            LOGE("napi-->DnsLookup success");
            RequestTask *requestTask = (RequestTask *)data;
            napi_value result;
            napi_create_string_utf8(env, requestTask->dnsText.c_str(), NAPI_AUTO_LENGTH, &result);
            napi_resolve_deferred(requestTask->env, requestTask->deferred, result);
            napi_delete_async_work(env, requestTask->asyncWork);
            delete requestTask;
            requestTask = nullptr;
        },
        requestTask, &requestTask->asyncWork);
    napi_queue_async_work(env, requestTask->asyncWork);
    return promise;
}

napi_value Http2Napi::OpenNativeLog(napi_env env, napi_callback_info info)
{
    g_ohosLogOn = true;
    return nullptr;
}